package com.ceprei.gui.service;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import com.ceprei.domain.common.BaseEntity;
import com.ceprei.gui.mapper.BasicMapper;
import com.google.common.collect.Lists;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Collectors;

/**
 * @author zhou minghao
 * @date 2024/11/29
 * @description
 */
public abstract class BasicServiceImpl <M extends BasicMapper<T>, T extends BaseEntity> extends ServiceImpl<M, T> implements BasicService<T> {
    protected static final Long TREE_ROOT_ID_LONG = 0L;
    protected static final Integer TREE_ROOT_ID_INTEGER = 0;
    protected static final String TREE_ROOT_ID_STRING = "0";

    @Override
    public List<T> listBatchByEntityList(List<T> entityList) {
        return entityList.stream()
                .flatMap(t -> list(t).stream())
                .distinct()
                .collect(Collectors.toList());
    }

    @Override
    public boolean updateIgnoreDelFlag(T t) {
        return SqlHelper.retBool(baseMapper.updateIgnoreDelFlag(t));
    }

    /**
     * 批量忽略删除状态的修改
     */
    @Override
    public boolean updateBatchIgnoreDelFlag(List<T> t) {
        final boolean[] result = {true};
        t.forEach(en -> {
            if (!updateIgnoreDelFlag(en)) {
                result[0] = false;
            }
        });
        return result[0];
    }

    /**
     * mysql多values的方式批量插入，默认3o条一次
     *
     * @param t 要插入的数据
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean insertBatchByMysql(List<T> t) {
        return insertBatchByMysql(t, 30);
    }

    /**
     * mysql多values的方式批量插入
     *
     * @param entityList 要插入的数据
     * @param batchSize  每次插入多少条
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean insertBatchByMysql(List<T> entityList, int batchSize) {
        if (CollectionUtils.isEmpty(entityList)) {
            return false;
        }
        List<List<T>> partition = Lists.partition(entityList, batchSize);
        for (List<T> ts : partition) {
            baseMapper.insertBatchByMysql(ts);
        }
        return true;
    }

    @Override
    public <Entity extends T> Page<Entity> queryPageVo(Page<Entity> page, Entity entity) {
        return baseMapper.queryPageVo(page, entity);
    }

    @Override
    public <Vo extends T> List<Vo> listVo(Vo vo) {
        try {
            return baseMapper.listVo(vo);
        } catch (Exception e) {
            List<T> list = list();
            if (CollectionUtils.isEmpty(list)) {
                return Collections.emptyList();
            }
            List<Vo> result = new LinkedList<>();
            long start = System.currentTimeMillis();
            try {
                for (T t : list) {
                    //测试证明 使用反射比 stream clone的方式快
                    Class<Vo> clazz = (Class<Vo>) vo.getClass();
                    Vo clone = clazz.newInstance();
//                    Vo clone = ObjectUtil.clone(vo);
                    BeanUtils.copyProperties(t, clone);
                    result.add(clone);
                }
                log.debug("list execute:{}");//System.currentTimeMillis() - start);
            } catch (Exception a) {
                log.error("list conversion vo fail.", a);
            }
            return result;
        }
    }

    @Override
    public <Vo extends T, R extends Serializable> List<Vo> buildTree(Supplier<Vo> getVo, R treeRootId, Function<Vo, R> getParentId, Function<Vo, R> getId, BiConsumer<Vo, List<Vo>> setChildren) {
        Vo vo = getVo.get();
        List<Vo> voList = listVo(vo);
        return buildTree(voList, treeRootId, getParentId, getId, setChildren);
    }

    @Override
    public <Vo extends T, R> List<Vo> buildTree(List<Vo> voList, R treeRootId, Function<Vo, R> getParentId, Function<Vo, R> getId, BiConsumer<Vo, List<Vo>> setChildren) {
        return buildTree(voList, treeRootId, getParentId, getId, setChildren, voEntity -> Objects.nonNull(getParentId.apply(voEntity)) && treeRootId.equals(getParentId.apply(voEntity)));
    }

    @Override
    public <Vo extends T, R> List<Vo> buildTree(List<Vo> voList, R treeRootId, Function<Vo, R> getParentId, Function<Vo, R> getId, BiConsumer<Vo, List<Vo>> setChildren, Predicate<Vo> parentFilter) {
        //基于父节点分组
        if (CollectionUtils.isNotEmpty(voList)) {
            Map<R, List<Vo>> parentMap = voList.stream()
                    .filter(voEntity -> Objects.nonNull(getParentId.apply(voEntity)))
                    .collect(Collectors.groupingBy(getParentId));
            //返回首级菜单
            return voList.stream().peek(voEntity -> {
                        List<Vo> vos = parentMap.get(getId.apply(voEntity));
                        if (CollectionUtils.isNotEmpty(vos)) {
                            setChildren.accept(voEntity, vos);
                        }
                    })
                    .filter(parentFilter)
                    .collect(Collectors.toList());
        }
        return Collections.emptyList();
    }
}
